package com.wl.shixun1.mymvc;


import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Fraction implements Num {
    private int f1, f2; // f1是分子, f2是分母

    private int gongyue(int a, int b) { // 求最大公约数
        int m, n, r;
        if (a > b) {
            m = a;
            n = b;
        } else {
            m = b;
            n = a;
        }
        while (n != 0) {
            r = m % n;
            m = n;
            n = r;
        }
        return m;
    }

    public Num add(Num x) {
        Fraction result = new Fraction();
        if (x instanceof MyInt) {
            // 分数与整数相加
            MyInt xx = (MyInt) x;
            result.f1 = f1 + xx.getF() * f2;
            result.f2 = f2;
        } else if (x instanceof MyDecimal) {
            // 分数与小数相加，转换为小数运算
            MyDecimal fx = new MyDecimal((double) f1 / f2);
            return fx.add(x);
        } else {
            // 分数与分数相加
            Fraction xx = (Fraction) x;
            result.f1 = f1 * xx.f2 + xx.f1 * f2;
            result.f2 = f2 * xx.f2;
        }
        int t = gongyue(result.f1, result.f2);
        result.f1 /= t;
        result.f2 /= t;
        return result;
    }

    public Num sub(Num x) {
        Fraction result = new Fraction();
        if (x instanceof MyInt) {
            // 分数与整数相减
            MyInt xx = (MyInt) x;
            result.f1 = f1 - xx.getF() * f2;
            result.f2 = f2;
        } else if (x instanceof MyDecimal) {
            // 分数与小数相减，转换为小数运算
            MyDecimal fx = new MyDecimal((double) f1 / f2);
            return fx.sub(x);
        } else {
            // 分数与分数相减
            Fraction xx = (Fraction) x;
            result.f1 = f1 * xx.f2 - xx.f1 * f2;
            result.f2 = f2 * xx.f2;
        }
        int t = gongyue(result.f1, result.f2);
        result.f1 /= t;
        result.f2 /= t;
        return result;
    }
    
    public Num mul(Num x) {
        Fraction result = new Fraction();
        if (x instanceof MyInt) {
            // 分数与整数相乘
            MyInt xx = (MyInt) x;
            result.f1 = f1 * xx.getF();
            result.f2 = f2;
        } else if (x instanceof MyDecimal) {
            // 分数与小数相乘，转换为小数运算
            MyDecimal fx = new MyDecimal((double) f1 / f2);
            return fx.mul(x);
        } else {
            // 分数与分数相乘
            Fraction xx = (Fraction) x;
            result.f1 = f1 * xx.f1;
            result.f2 = f2 * xx.f2;
        }
        int t = gongyue(result.f1, result.f2);
        result.f1 /= t;
        result.f2 /= t;
        return result;
    }
    
    public Num div(Num x) {
        Fraction result = new Fraction();
        if (x instanceof MyInt) {
            // 分数除以整数
            MyInt xx = (MyInt) x;
            if (xx.getF() == 0) {
                throw new ArithmeticException("除数不能为零");
            }
            result.f1 = f1;
            result.f2 = f2 * xx.getF();
        } else if (x instanceof MyDecimal) {
            // 分数除以小数，转换为小数运算
            MyDecimal fx = new MyDecimal((double) f1 / f2);
            return fx.div(x);
        } else {
            // 分数除以分数
            Fraction xx = (Fraction) x;
            if (xx.f1 == 0) {
                throw new ArithmeticException("除数不能为零");
            }
            result.f1 = f1 * xx.f2;
            result.f2 = f2 * xx.f1;
        }
        int t = gongyue(result.f1, result.f2);
        result.f1 /= t;
        result.f2 /= t;
        return result;
    }

    public String draw1() {
        String s;
        if (f2 == 1) {
            s = f1 + "";
        } else if (f1 * f2 > 0) {
            s = Math.abs(f1) + "/" + Math.abs(f2);
        } else {
            s = "-" + Math.abs(f1) + "/" + Math.abs(f2);
        }
        return s;
    }
    
    // 实现三个数的表达式计算，根据运算符优先级进行计算
    @Override
    public Num calculateExpression(Num num2, Num num3, String op1, String op2) {
        // 先判断运算符优先级
        if ((op1.equals("mul") || op1.equals("div")) && (op2.equals("add") || op2.equals("sub"))) {
            // 如果第一个运算符是乘除，第二个是加减，则先计算第一个
            Num temp = this;
            switch (op1) {
                case "mul":
                    temp = this.mul(num2);
                    break;
                case "div":
                    temp = this.div(num2);
                    break;
                case "add":
                    temp = this.add(num2);
                    break;
                case "sub":
                    temp = this.sub(num2);
                    break;
            }
            
            // 然后计算第二个运算符
            switch (op2) {
                case "mul":
                    return temp.mul(num3);
                case "div":
                    return temp.div(num3);
                case "add":
                    return temp.add(num3);
                case "sub":
                    return temp.sub(num3);
            }
        } else if ((op2.equals("mul") || op2.equals("div")) && (op1.equals("add") || op1.equals("sub"))) {
            // 如果第二个运算符是乘除，第一个是加减，则先计算第二个
            Num temp = num2;
            switch (op2) {
                case "mul":
                    temp = num2.mul(num3);
                    break;
                case "div":
                    temp = num2.div(num3);
                    break;
                case "add":
                    temp = num2.add(num3);
                    break;
                case "sub":
                    temp = num2.sub(num3);
                    break;
            }
            
            // 然后计算第一个运算符
            switch (op1) {
                case "mul":
                    return this.mul(temp);
                case "div":
                    return this.div(temp);
                case "add":
                    return this.add(temp);
                case "sub":
                    return this.sub(temp);
            }
        } else {
            // 如果运算符优先级相同，则从左到右计算
            Num temp = this;
            switch (op1) {
                case "mul":
                    temp = this.mul(num2);
                    break;
                case "div":
                    temp = this.div(num2);
                    break;
                case "add":
                    temp = this.add(num2);
                    break;
                case "sub":
                    temp = this.sub(num2);
                    break;
            }
            
            // 然后计算第二个运算符
            switch (op2) {
                case "mul":
                    return temp.mul(num3);
                case "div":
                    return temp.div(num3);
                case "add":
                    return temp.add(num3);
                case "sub":
                    return temp.sub(num3);
            }
        }
        
        return null;
    }
}